{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "0",
   "metadata": {},
   "source": [
    "[![image](https://jupyterlite.rtfd.io/en/latest/_static/badge.svg)](https://demo.leafmap.org/lab/index.html?path=notebooks/102_fused.ipynb)\n",
    "[![image](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/opengeos/leafmap/blob/master/docs/notebooks/102_fused.ipynb)\n",
    "[![image](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/opengeos/leafmap/HEAD)\n",
    "\n",
    "**Mapping Overture Buildings and Foursquare Places with Leafmap + Fused**\n",
    "\n",
    "Fetch data by calling [Fused UDFs](https://docs.fused.io/core-concepts/write/) and render it on a [Leafmap](https://leafmap.org/) map.\n",
    "\n",
    "This notebook shows how you can:\n",
    "\n",
    "1. Load [Overture Buildings](https://docs.overturemaps.org/getting-data/fused) for a drawn area\n",
    "2. Load [Foursquare (FSQ) Place](https://docs.foursquare.com/data-products/docs/access-fsq-os-places) POIs for a drawn area"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1",
   "metadata": {},
   "outputs": [],
   "source": [
    "# %pip install fused>=1.11.1 \"leafmap[maplibre]\" -q"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import pandas as pd\n",
    "import geopandas as gpd\n",
    "from shapely.geometry import shape\n",
    "import fused\n",
    "import leafmap\n",
    "import leafmap.maplibregl as maplibre"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3",
   "metadata": {},
   "source": [
    "## 1. Load Overture Buildings for drawn area\n",
    "\n",
    "First draw a bounding box over an area of interest (AOI) and create a GeoDataFrame with it. Then, [run the Overture UDF](https://docs.fused.io/core-concepts/run/) to fetch data for that AOI.\n",
    "\n",
    "### 1.1 First, draw an AOI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(center=[40.713370, -73.996181], zoom=14)\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# If no AOI is drawn, use the default AOI\n",
    "\n",
    "if m.user_roi is None:\n",
    "    m.user_roi = {\n",
    "        \"type\": \"Feature\",\n",
    "        \"properties\": {},\n",
    "        \"geometry\": {\n",
    "            \"type\": \"Polygon\",\n",
    "            \"coordinates\": [\n",
    "                [\n",
    "                    [-74.025621, 40.699967],\n",
    "                    [-74.025621, 40.730283],\n",
    "                    [-73.966055, 40.730283],\n",
    "                    [-73.966055, 40.699967],\n",
    "                    [-74.025621, 40.699967],\n",
    "                ]\n",
    "            ],\n",
    "        },\n",
    "    }"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6",
   "metadata": {},
   "source": [
    "### 1.2 Then, convert it to a GeoDataFrame."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7",
   "metadata": {},
   "outputs": [],
   "source": [
    "import geopandas as gpd\n",
    "\n",
    "# Convert drawing to GeoDataFrame\n",
    "gdf_drawing = gpd.GeoDataFrame(\n",
    "    [m.user_roi[\"properties\"]], geometry=[shape(m.user_roi[\"geometry\"])]\n",
    ")\n",
    "\n",
    "gdf_drawing"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8",
   "metadata": {},
   "source": [
    "### 1.3 Fetch Overture Buildings for the AOI and render them on the map\n",
    "\n",
    "The data comes from calling the \"[Overture Maps Example](https://www.fused.io/workbench/catalog/Overture_Maps_Example-64071fb8-2c96-4015-adb9-596c3bac6787)\" public UDF with `fused.run`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Fetch Overture Buildings GDF with Fused UDF\n",
    "gdf = fused.run(\"UDF_Overture_Maps_Example\", bbox=gdf_drawing)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "10",
   "metadata": {},
   "outputs": [],
   "source": [
    "gdf.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(f\"The number of buildings within the AOI: {len(gdf)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "12",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Add GDF to map\n",
    "m.add_gdf(\n",
    "    gdf[[\"id\", \"geometry\", \"height\", \"class\"]],\n",
    "    layer_type=\"fill\",\n",
    "    name=\"Buildings\",\n",
    "    fill_colors=[\"red\"],\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13",
   "metadata": {},
   "source": [
    "### 1.4 Visualize buildings in 3D."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "14",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = maplibre.Map(pitch=60)\n",
    "m.add_basemap(\"USGS.USImagery\")\n",
    "gdf_filter = gdf[gdf.height > 0][[\"id\", \"geometry\", \"height\", \"class\"]]\n",
    "m.add_data(gdf_filter, column=\"height\", cmap=\"Blues\", extrude=True, name=\"Buildings\")\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "15",
   "metadata": {},
   "outputs": [],
   "source": [
    "m.layer_interact()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "16",
   "metadata": {},
   "source": [
    "## 2. Load FSQ Places POIs for drawn area\n",
    "\n",
    "### 2.1 Fetch FSQ Places for the AOI (defined above) and render them on the map\n",
    "\n",
    "The data comes from calling the \"[Foursquare Open Source Places](https://www.fused.io/workbench/catalog/Foursquare_Open_Source_Places-5cd75ead-e319-4279-8efc-04276de145bc)\" public UDF with `fused.run`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "17",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Fetch FSQ GDF with Fused UDF\n",
    "gdf = fused.run(\"UDF_Foursquare_Open_Source_Places\", bbox=gdf_drawing)\n",
    "\n",
    "# `add_points_from_xy` requires latitude and longitude columns\n",
    "gdf[\"latitude\"] = gdf.geometry.y\n",
    "gdf[\"longitude\"] = gdf.geometry.x\n",
    "\n",
    "# Show place categories\n",
    "set(gdf.level1_category_name.values)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "18",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Subsample the gdf\n",
    "gdf_sample = (\n",
    "    gdf[[\"name\", \"latitude\", \"longitude\", \"geometry\"]].head(200).reset_index(drop=True)\n",
    ")\n",
    "# gdf_sample = gdf[gdf.level1_category_name == 'Dining and Drinking'][['name', 'latitude', 'longitude']].head(1000).reset_index(drop=True)\n",
    "gdf_sample"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "19",
   "metadata": {},
   "source": [
    "### 2.2 Visualize the POIs on a 2d map"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "20",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(center=[40.713370, -73.996181], zoom=14)\n",
    "# Add as marker cluster\n",
    "m.add_points_from_xy(\n",
    "    gdf_sample,\n",
    "    x=\"longitude\",\n",
    "    y=\"latitude\",\n",
    "    spin=False,\n",
    "    add_legend=True,\n",
    ")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "21",
   "metadata": {},
   "source": [
    "### 2.3 Visualize POIs with OpenStreetMap vector tiles"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "22",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = maplibre.Map(pitch=60, style=\"https://maps.gishub.org/styles/openstreetmap.json\")\n",
    "m.add_gdf(gdf_sample, name=\"Places\")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "23",
   "metadata": {},
   "source": [
    "### 2.4 Visualize the POIs on a 3D map with Overture buildings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "24",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = maplibre.Map(zoom=18, pitch=60, style=\"positron\")\n",
    "m.add_overture_3d_buildings()\n",
    "m.add_gdf(gdf_sample, name=\"Places\")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "25",
   "metadata": {},
   "source": [
    "### 2.5 Visualize the POIs on a 3D map with [OpenFreeMap](https://openfreemap.org/) vector tiles"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "26",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = maplibre.Map(pitch=60, style=\"liberty\")\n",
    "m.add_gdf(gdf_sample, name=\"Places\")\n",
    "m"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
